package com.jinyi.wwdeng.autodialer.crash

import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.os.Environment
import android.os.StatFs
import android.util.Log
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
import java.io.PrintWriter
import java.io.StringWriter
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

/**
 * 异常信息 并存到SD卡
 */
class GlobalExceptionHandler private constructor() : Thread.UncaughtExceptionHandler {

    companion object {
        private const val TAG = "GlobalExceptionHandler"
        @SuppressLint("StaticFieldLeak")
        private var instance: GlobalExceptionHandler? = null

        fun getInstance(): GlobalExceptionHandler {
            return instance ?: synchronized(this) {
                instance ?: GlobalExceptionHandler().also { instance = it }
            }
        }
    }

    private lateinit var context: Context
    private var defaultHandler: Thread.UncaughtExceptionHandler? = null
    private var crashListener: OnCrashListener? = null

    /**
     * 初始化异常处理器
     */
    fun init(context: Context) {
        this.context = context.applicationContext
        this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
        Thread.setDefaultUncaughtExceptionHandler(this)
    }

    /**
     * 设置崩溃监听器
     */
    fun setOnCrashListener(listener: OnCrashListener) {
        this.crashListener = listener
    }

    override fun uncaughtException(thread: Thread, ex: Throwable) {
        // 处理异常并保存日志
        val logPath = saveCrashLog(ex)

        // 通知监听器
        crashListener?.onCrash(thread, ex, logPath)

        // 调用默认处理器（通常会终止应用）
        defaultHandler?.uncaughtException(thread, ex)
    }

    /**
     * 保存崩溃日志到文件
     */
    private fun saveCrashLog(ex: Throwable): String? {
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
        val fileName = "crash_log_$timeStamp.txt"

        val logFile = getLogFile(fileName) ?: return null

        return try {
            BufferedWriter(FileWriter(logFile)).use { writer ->
                // 写入设备信息
                writeDeviceInfo(writer)

                // 写入异常信息
                writer.write("=== CRASH STACK TRACE ===\n")
                val sw = StringWriter()
                val pw = PrintWriter(sw)
                ex.printStackTrace(pw)
                writer.write(sw.toString())
                writer.write("\n\n")

                // 写入内存信息
                writeMemoryInfo(writer)
            }
            logFile.absolutePath
        } catch (e: IOException) {
            Log.e(TAG, "Error writing crash log", e)
            null
        }
    }

    /**
     * 获取日志文件（存储到SD卡Download文件夹）
     */
    private fun getLogFile(fileName: String): File? {
        // 检查SD卡是否可用
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Log.e(TAG, "External storage not available")
            return null
        }

        // 获取Download目录
        val downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)

        // 创建CrashLogs子目录
        val crashLogsDir = File(downloadDir, "CrashLogs")

        // 创建目录（如果不存在）
        if (!crashLogsDir.exists() && !crashLogsDir.mkdirs()) {
            Log.e(TAG, "Failed to create log directory: ${crashLogsDir.absolutePath}")
            return null
        }

        return File(crashLogsDir, fileName)
    }

    /**
     * 写入设备信息
     */
    @Throws(IOException::class)
    private fun writeDeviceInfo(writer: BufferedWriter) {
        writer.write("=== DEVICE INFORMATION ===\n")
        writer.write("Time: ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())}\n")
        writer.write("Model: ${Build.MODEL}\n")
        writer.write("Brand: ${Build.BRAND}\n")
        writer.write("Device: ${Build.DEVICE}\n")
        writer.write("Product: ${Build.PRODUCT}\n")
        writer.write("Android Version: ${Build.VERSION.RELEASE}\n")
        writer.write("API Level: ${Build.VERSION.SDK_INT}\n")
        writer.write("Manufacturer: ${Build.MANUFACTURER}\n")
        writer.write("\n")
    }

    /**
     * 写入内存信息
     */
    @Throws(IOException::class)
    private fun writeMemoryInfo(writer: BufferedWriter) {
        writer.write("=== MEMORY INFORMATION ===\n")

        // 获取存储空间信息
        val statFs = StatFs(Environment.getDataDirectory().path)
        val blockSize = statFs.blockSizeLong
        val totalBlocks = statFs.blockCountLong
        val availableBlocks = statFs.availableBlocksLong

        writer.write("Total Storage: ${formatFileSize(totalBlocks * blockSize)}\n")
        writer.write("Available Storage: ${formatFileSize(availableBlocks * blockSize)}\n")

        // 获取运行时内存信息
        val runtime = Runtime.getRuntime()
        writer.write("Max Memory: ${formatFileSize(runtime.maxMemory())}\n")
        writer.write("Total Memory: ${formatFileSize(runtime.totalMemory())}\n")
        writer.write("Free Memory: ${formatFileSize(runtime.freeMemory())}\n")
        writer.write("Used Memory: ${formatFileSize(runtime.totalMemory() - runtime.freeMemory())}\n")
    }

    /**
     * 格式化文件大小
     */
    private fun formatFileSize(size: Long): String {
        if (size <= 0) return "0 B"

        val units = arrayOf("B", "KB", "MB", "GB", "TB")
        val digitGroups = (Math.log10(size.toDouble()) / Math.log10(1024.0)).toInt()

        return "%.2f %s".format(Locale.getDefault(), size / Math.pow(1024.0, digitGroups.toDouble()), units[digitGroups])
    }

    /**
     * 获取所有崩溃日志文件
     */
    fun getAllCrashLogs(): Array<File> {
        // 检查SD卡是否可用
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            return emptyArray()
        }

        val downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
        val crashLogsDir = File(downloadDir, "CrashLogs")

        return if (crashLogsDir.exists() && crashLogsDir.isDirectory) {
            crashLogsDir.listFiles { _, name -> name.endsWith(".txt") } ?: emptyArray()
        } else {
            emptyArray()
        }
    }

    /**
     * 删除所有崩溃日志
     */
    fun deleteAllCrashLogs(): Boolean {
        val logFiles = getAllCrashLogs()
        var success = true

        for (file in logFiles) {
            if (!file.delete()) {
                success = false
            }
        }

        return success
    }

    /**
     * 获取最新的崩溃日志文件
     */
    fun getLatestCrashLog(): File? {
        val logFiles = getAllCrashLogs()
        return logFiles.maxByOrNull { it.lastModified() }
    }

    /**
     * 崩溃监听接口
     */
    fun interface OnCrashListener {
        fun onCrash(thread: Thread, ex: Throwable, logPath: String?)
    }

}